package simpleWave;

import java.util.ArrayList;
import java.util.LinkedList;

import data.PersonData;
import data.Stadium;
import data.Wave;

public class PersonProcess extends Thread {
	
	private PersonData personData;

	private ArrayList<PersonProcess> persons;

	private boolean isWaveStarter = false;
	private boolean isRandomlyStartingWaves = true;
	private int startingWaveChance = 2;
	
	private boolean verifiedWave;
	
	private Synchronizer synchronizer;
	
	private ArrayList<Stadium> history;
	
	private ArrayList<String> lines;

	public synchronized ArrayList<Stadium> getHistory() {
		return history;
	}

	public void setHistory(ArrayList<Stadium> history) {
		this.history = history;
	}

	public PersonProcess(Synchronizer synchronizer) {
		this.synchronizer = synchronizer;
	}

	public void run() {
		// run verifier?
		init();
		while (true) {
			if (isRandomlyStartingWaves) {
				considerStartingWave();
			}
			
			boolean neighbourStanding = lookAround();
			
			//this.synchronizer.checkIn(this.getId());
			
			if (neighbourStanding) {
				this.standUp();
				
				this.synchronizer.checkIn(this.getId());
				
				this.sitDown();
				
				this.synchronizer.checkIn(this.getId());
			}
			
			this.synchronizer.checkIn(this.getId());
			
		}
	}

	private void init() {
		if (isWaveStarter) {
			startWave();
		}
	}
	
	private void considerStartingWave() {
		int chance = (int) Math.round(Math.random() * 99) + 1;
		if (startingWaveChance >= chance) {
			startWave2();
		}
	}
	
	public boolean lookAround() {
		return (lookRight() || lookLeft() || lookForWave());
		/*try {
			sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	}
	
	// Fix so verifier uses person data and not strings
	private boolean lookForWave() {
		if (lines.size() > 0) {
			ArrayList<Wave> waves = Verifier.verify(lines);
			
			for (Wave wave : waves) {
				if (wave.endPosition == (this.personData.getPersonId()+1)) {
					return true;
				}
			}
		}
		
		return false;
	}

	private boolean lookRight() {
		// If no history exists, we have nothing to look at
		if (history.size() < 1) {
			return false;
		}
		
		// Retrieve latest stadium, if none return false
		Stadium stadium = history.get(history.size()-1);
		
		// Retrieve row
		ArrayList<PersonData> row = stadium.getRow();
		
		//If we are last in row, there can't be nobody to the right
		if (personData.getPersonId() >= (row.size()-1)) {
			return false;
		}
		
		// Retrieve person to right, if any
		PersonData personToRight = row.get(personData.getPersonId()+1);
		if (personToRight.getPersonState() == PersonData.PersonState.STANDING
				&& personToRight.getStartDirection() == PersonData.StartDirection.LEFT) {
			return true;
		} else {
			return false;
		}
	}
	
	private boolean lookLeft() {
		return false;
		// If no history exists, we have nothing to look at
		/*if (history.size() < 1) {
			return false;
		}
		
		// Retrieve latest stadium, if none return false
		Stadium stadium = history.get(history.size()-1);
		
		// Retrieve row
		ArrayList<PersonData> row = stadium.getRow();
		
		// If we are first in row, there can be nobody to the left
		if (personData.getPersonId() <= 0) {
			return false;
		}
		
		// Retrieve person to left, if any
		PersonData personToLeft = row.get(personData.getPersonId()-1);
		if (personToLeft.getPersonState() == PersonData.PersonState.STANDING) {
			return true;
		} else {
			return false;
		}*/
	}
	
	private void scheduleJoinWave(int numTimeUnits) {
		for (int i = numTimeUnits; i > 0; i--) {
			this.synchronizer.checkIn(this.getId());
		}
		this.joinWave();
	}
	
	private void startWave() {
		
		this.synchronizer.checkIn(this.getId());
		
		
		/*if (personData.getPersonId() < 2) {
			
			
		} else if ((history.get(0).getRow().size()-1) > (personData.getPersonId() - 2)) {
			// We are at right end Do a left wave
		}*/
		
		standUp();
		this.personData.setStartDirection(PersonData.StartDirection.LEFT);
		
		this.synchronizer.checkIn(this.getId());
		sitDown();
		this.personData.setStartDirection(PersonData.StartDirection.NONE);
		this.synchronizer.checkIn(this.getId());
		this.synchronizer.checkIn(this.getId());
	}
	
	private void startWave2() {
		
		this.synchronizer.checkIn(this.getId());
		
		
		/*if (personData.getPersonId() < 2) {
			
			
		} else if ((history.get(0).getRow().size()-1) > (personData.getPersonId() - 2)) {
			// We are at right end Do a left wave
		}*/
		
		standUp();
		
		this.synchronizer.checkIn(this.getId());
		sitDown();
		this.synchronizer.checkIn(this.getId());
		this.synchronizer.checkIn(this.getId());
	}
	
	private void joinWave() {
		
		this.synchronizer.checkIn(this.getId());
		standUp();
		this.synchronizer.checkIn(this.getId());
		sitDown();
		this.synchronizer.checkIn(this.getId());
		this.synchronizer.checkIn(this.getId());
	}

	public void standUp() {
		/*try {
			sleep(1000);
		} catch (InterruptedException e) {
			System.out.println("Sleep failed");
			e.printStackTrace();
		}*/
		this.personData.setPersonState(PersonData.PersonState.STANDING);
	}
	
	public void sitDown() {
		/*try {
			sleep(1000);
		} catch (InterruptedException e) {
			System.out.println("Sleep failed");
			e.printStackTrace();
		}*/
		this.personData.setPersonState(PersonData.PersonState.SITTING);
		/*try {
			sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	}
	
	public String toString() {
		return this.personData.toString();
	}
	
	public ArrayList<PersonProcess> getPersons() {
		return persons;
	}

	public void setPersons(ArrayList<PersonProcess> persons) {
		this.persons = persons;
	}

	public PersonData getPersonData() {
		return personData;
	}

	public void setPersonData(PersonData personData) {
		this.personData = personData;
	}

	public boolean isRandomlyStartingWaves() {
		return isRandomlyStartingWaves;
	}

	public void setRandomlyStartingWaves(boolean isRandomlyStartingWaves) {
		this.isRandomlyStartingWaves = isRandomlyStartingWaves;
	}

	public boolean isWaveStarter() {
		return isWaveStarter;
	}

	public void setWaveStarter(boolean waveStarter) {
		this.isWaveStarter = waveStarter;
	}

	public void setVerifiedWave(boolean verifiedWave) {
		this.verifiedWave = verifiedWave;
	}

	public boolean isVerifiedWave() {
		return verifiedWave;
	}

	public void setLines(ArrayList<String> lines) {
		this.lines = lines;
	}

	public ArrayList<String> getLines() {
		return lines;
	}
}
